package org.metasketch.simulator.tools.resources;

import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import org.metasketch.demo.model.ActorRole;
import org.metasketch.demo.model.DEMOModel;
import org.metasketch.demo.model.TransactionKind;
import org.metasketch.simulator.petri.PetriNet;
import org.metasketch.simulator.petri.PetriNetSet;
import org.metasketch.simulator.petri.Transition;
import org.metasketch.simulator.resources.Resource;
import org.metasketch.simulator.resources.ResourceBank;
import org.metasketch.simulator.resources.ResourceBase;
import org.metasketch.simulator.resources.ResourceClass;
import org.metasketch.simulator.resources.ResourceRequirements;
import org.metasketch.simulator.runtime.ExpressionEngine;
import org.metasketch.simulator.tools.Registry;
import org.metasketch.simulator.tools.generic.Expression;
import org.metasketch.simulator.tools.generic.GenericInfo;
import org.metasketch.simulator.tools.generic.ResourceProduction;
import org.metasketch.simulator.tools.generic.ResourceRequirement;
import org.metasketch.simulator.tools.generic.Variable;
import org.metasketch.simulator.transformation.PetriNetSimulationPackage;

import com.thoughtworks.xstream.XStream;

public class MainResourcesDefinitionLoader {

	protected static XStream getXStream() {
		XStream xstream = new XStream();
		xstream.autodetectAnnotations(true);

		xstream.processAnnotations(Alias.class);
		xstream.processAnnotations(BasicResource.class);

		xstream.processAnnotations(MainResources.class);

		return xstream;
	}

	public static MainResources load(File file) throws Throwable {

		XStream xstream = getXStream();

		FileReader reader = new FileReader(file);
		MainResources cfg = (MainResources) xstream.fromXML(reader);
		reader.close();

		return cfg;

	}

	public static MainResources getResources(
			PetriNetSimulationPackage simulationPackage, File file)
			throws Throwable {
		MainResources cfg = load(file);

		Registry reg = simulationPackage.getRegistry();
		ResourceBank bank = simulationPackage.getResources();

		// process the aliases
		List<Alias> aliases = cfg.getAliases();
		for (Alias alias : aliases) {

			ResourceBase resource = bank.getByInitialIdentifier(alias
					.getPartialKey());
			if (resource == null)
				throw new Exception("Can't find the resource with partial key "
						+ alias.getPartialKey());

			reg.register(alias.getAlias(), resource);

		}

		// process new resources
		List<BasicResource> resources = cfg.getResources();
		for (BasicResource resource : resources) {

			Resource r = new Resource();
			r.setName(resource.getName());
			r.setRestorable(resource.isRestorable());
			r.setIdentifier(resource.getAlias());
			// read expression...
			r.setQuantity(ExpressionEngine.getLong(resource
					.getQuantityExpression()));

			reg.register(resource.getAlias(), r);

		}

		// process resource classes
		// first just add them
		List<BasicResourceClass> classes = cfg.getResourceClasses();
		for (BasicResourceClass type : classes) {

			ResourceClass r = new ResourceClass();
			r.setName(type.getName());
			r.setIdentifier(type.getAlias());
			// read expression...
			reg.register(type.getAlias(), r);

		}

		// now process which resource classes they belong to and which
		// parent..etc
		// List<BasicResourceClass> classes = cfg.getResourceClasses();
		for (BasicResourceClass type : classes) {

			ResourceClass resourceClass = (ResourceClass) reg.get(type
					.getAlias());

			StringTokenizer st = new StringTokenizer(type.getResources());
			List<String> childrenAliases = new ArrayList<String>();
			while (st.hasMoreTokens()) {
				childrenAliases.add(st.nextToken());
			}

			for (String alias : childrenAliases) {
				ResourceBase child = (ResourceBase) reg.get(alias);

				if (child == null)
					throw new Exception("No child resource named " + alias
							+ " as found for resource class " + type.getName()
							+ " aka " + type.getAlias());

				child.addClass(resourceClass);
				resourceClass.addResource(child);
			}

		}

		return cfg;

	}

}
